from initial import initial
from PPMCC import PPMCC
from RMSE import RMSE
from neighbour_related import *
import numpy as np

def neighbour_based_i2i(ford_train_data,ford_user_index,userId,movieId,rating):
    g=20 #初始g
    beta=10
    lamb=10
    epsilon=pow(10,-4)
    m=ford_user_index.shape[0]-1 #总用户数
    '''
        Part1 寻找与i最相似的g个物品(这g个物品需要被当前用户评过分)
    '''
    most_similar_movies,current_userlist,rating_threshold,flag=find_g_similar_movies(g,beta,ford_train_data,ford_user_index,userId,movieId)
    '''
        Part2 计算A，B矩阵    
    '''
    if flag==-1:
        return -1
    else:
        g=most_similar_movies.shape[0]
        sij = np.zeros([g, ])  # size=g*1
        A = np.zeros([g, g])
        B = np.zeros([g, g])
        for j in range(A.shape[0]):
            for k in range(j,A.shape[1]):
                if j==k:
                    userlist = find_users_liked_currentmovie(ford_train_data, ford_user_index, most_similar_movies[j],rating_threshold)
                    userlist=userlist[np.in1d(userlist,current_userlist,assume_unique=True)] #同时对i，j进行了评分的人
                    for u in range(userlist.shape[0]):
                        rvj=find_rating_byMovieAndUser(ford_train_data,ford_user_index,userlist[u],most_similar_movies[j])
                        rvi=find_rating_byMovieAndUser(ford_train_data,ford_user_index,userlist[u],movieId)
                        A[j,k]+=(rvj-rvi)*(rvj-rvi)
                        B[j,k]+=1
                else:
                    userlist1 = find_users_liked_currentmovie(ford_train_data, ford_user_index, most_similar_movies[j],
                                                             rating_threshold)
                    userlist1 = userlist1[np.in1d(userlist1, current_userlist, assume_unique=True)]  # 同时对i，j进行了评分的人
                    userlist2 = find_users_liked_currentmovie(ford_train_data, ford_user_index, most_similar_movies[k],
                                                              rating_threshold)
                    userlist2 = userlist2[np.in1d(userlist2, current_userlist, assume_unique=True)]  # 同时对i，k进行了评分的人
                    userlist=userlist1[np.in1d(userlist1,userlist2,assume_unique=True)] #同时对i,j,k进行了评分的人
                    for u in range(userlist.shape[0]):
                        rvj = find_rating_byMovieAndUser(ford_train_data, ford_user_index, userlist[u],
                                                         most_similar_movies[j])
                        rvi = find_rating_byMovieAndUser(ford_train_data, ford_user_index, userlist[u], movieId)
                        rvk=find_rating_byMovieAndUser(ford_train_data, ford_user_index, userlist[u],
                                                         most_similar_movies[k])
                        A[j, k] += (rvj - rvi)*(rvk - rvi)
                        B[j,k]+=1
        avg=np.average(A)
        A=(A*B+beta*avg)/(B+beta)
    '''
        Part3 二次规划迭代求解
    '''
    A=A+lamb
    b=np.ones([g,1])*lamb
    s=np.zeros([g,1])
    while 1:
        r=np.dot(A,s)-b
        for i in range(g):
            if (s[i,0]==0) & (r[i,0]<0):
                r[i,0]=0
        alpha=np.dot(r.T,r)/(np.dot(np.dot(r.T,A),r))
        for i in range(g):
            if r[i,0]<0:
                alpha=np.min(alpha,-s[i,0]/r[i,0])
        s=s+alpha*r
        if np.sum(np.abs(r))/g<epsilon:
            break
    rui_upper=0
    rui_down=0
    for j in range(g):
        ruj=find_rating_byMovieAndUser(ford_train_data, ford_user_index, userId,
                                                         most_similar_movies[j])
        rui_upper+=s[j,0]*ruj
        rui_down+=s[j,0]
    rui=rui_upper/rui_down
    rmse= RMSE(rui,rating)
    return rmse



def neighbour_based_u2u():
    RMSE=0
    return RMSE

def svd():
    RMSE=0
    return RMSE

def control():
    K=5
    train_data,valid_data,test_data,user_index,flag=initial(K)
    if flag==-1:
        print('Initial error')
        return -1
    else:
        avg_RMSE=0
        for i in range(test_data['userId'].shape[0]):
            single_RMSE=0
            for j in range(K):
                single_RMSE+=neighbour_based_i2i(train_data[j],user_index[j],test_data['userId'][i],test_data['movieId'][i],test_data['rating'][i])
            single_RMSE=single_RMSE/K
            avg_RMSE+=single_RMSE
        avg_RMSE=avg_RMSE/test_data['userId'].shape[0]


control()

